package com.jawmask.android.discover.ui;

import java.util.List;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.location.Address;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.Display;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.Toast;

import com.google.android.maps.MapActivity;
import com.jawmask.android.discover.R;
import com.jawmask.android.discover.bean.GPSLocation;
import com.jawmask.android.discover.bean.task.GetUserLocationAddressTask;
import com.jawmask.android.discover.utils.AppConstants;
import com.jawmask.android.discover.utils.ValidationUtils;

public abstract class BaseMapActivity extends MapActivity implements LocationListener {

	private final int MIN_GPS_LOCATION_UPDATION_TIME_DELAY = 60000;
	private final double TOAST_HEIGHT_RATIO = 0.17;

	private LocationManager locationManager;

	private String notificationMessage;
	private int userLastKnownLocationTimeOut;

	/***** Life Cycle Methods *********************/

	@Override
	protected void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		userLastKnownLocationTimeOut = Integer.parseInt(getString(R.string.user_location_time_out));
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	/***** GPS Related Methods *********************/

	public boolean enableMyLocation() {
		List<String> providers = locationManager.getAllProviders();
		boolean isEnabled = false;

		if (providers.contains(LocationManager.GPS_PROVIDER) && locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_GPS_LOCATION_UPDATION_TIME_DELAY, 0L, this);
			isEnabled = true;
		} else if (providers.contains(LocationManager.NETWORK_PROVIDER) && locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
			locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_GPS_LOCATION_UPDATION_TIME_DELAY, 0L, this);
			isEnabled = true;
		}
		return isEnabled;
	}

	public void disableMyLocation() {
		locationManager.removeUpdates(this);
	}

	protected Location getLastKnowLocation() {
		List<String> providers = locationManager.getAllProviders();

		if (providers.contains(LocationManager.GPS_PROVIDER) && locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			return locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		} else if (providers.contains(LocationManager.NETWORK_PROVIDER) && locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
			return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
		}
		return null;
	}

	public boolean isUserLastKnowLocationTimedOut(final Location lastKnownLocation) {
		return currentTime() - lastKnownLocation.getTime() > userLastKnownLocationTimeOut;
	}

	@Override
	public void onLocationChanged(Location userLocation) {
		receivedData();
		GPSLocation gpsLocation = new GPSLocation();
		gpsLocation.setLatitude(userLocation.getLatitude());
		gpsLocation.setLongitude(userLocation.getLongitude());
		getGetUserLocationAddressTask().execute(gpsLocation);
		disableMyLocation();
	}

	@Override
	public void onProviderDisabled(String provider) {
	}

	@Override
	public void onProviderEnabled(String provider) {
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
	}

	protected GetUserLocationAddressTask getGetUserLocationAddressTask() {
		return new GetUserLocationAddressTask(this) {

			protected void onPreExecute() {
				waitForData(getString(R.string.notification_msg_get_address));
			}

			protected void onPostExecute(final Address userAddress) {
				receivedData();
				if (userAddress != null) {
					updateUserAddress(userAddress);
				} else {
					showDialog(AppConstants.DIALOG_ID_NETWORK_NOT_AVAILABLE);
				}
			}
		};
	}

	protected String parseAddress(final Address address) {
		StringBuffer addressBuffer = new StringBuffer();
		for (int i = 0; i <= 9; i++) {
			try {
				String addressLine = address.getAddressLine(i);
				if (!ValidationUtils.isNullOrEmpty(addressLine))
					addressBuffer.append(address.getAddressLine(i));
			} catch (IllegalArgumentException e) {
				break;
			}
		}
		return addressBuffer.toString();
	}

	/***** Utility Methods *********************/

	private static int currentTime() {
		return Long.valueOf(System.currentTimeMillis() / 1000).intValue();
	}

	protected int getMeasuredHeight() {
		WindowManager w = getWindowManager();
		Display d = w.getDefaultDisplay();
		return d.getHeight();
	}

	protected abstract void updateUserAddress(final Address userAddress);

	/***** Dialog related Methods *********************/

	public void waitForData(final String notificationMessage) {
		this.notificationMessage = notificationMessage;
		showDialog(AppConstants.DIALOG_ID_PROGRESS_BAR);
	}

	public void receivedData() {
		try {
			removeDialog(AppConstants.DIALOG_ID_PROGRESS_BAR);
		} catch (IllegalArgumentException e) {

		}
	}

	public void showNotification(final String notificationMessage) {
		this.notificationMessage = notificationMessage;
		showDialog(AppConstants.DIALOG_ID_ERROR_NOTIFICATION);
	}

	protected void showErrorMessageToast(String message) {
		Toast toast = Toast.makeText(this, message == null ? "" : message.trim(), Toast.LENGTH_LONG);
		toast.setGravity(Gravity.TOP, 0, (int) (getMeasuredHeight() * TOAST_HEIGHT_RATIO));
		toast.show();
	}

	@Override
	protected Dialog onCreateDialog(int dialogId) {
		Dialog dialog = null;

		switch (dialogId) {
		case AppConstants.DIALOG_ID_PROGRESS_BAR:
			ProgressDialog progressDialog = new ProgressDialog(this);
			progressDialog.setMessage(this.notificationMessage);
			dialog = progressDialog;
			break;
		case AppConstants.DIALOG_ID_NETWORK_NOT_AVAILABLE:
			Builder builder = new AlertDialog.Builder(this);
			builder.setMessage(getString(R.string.error_msg_network_not_available));
			builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					System.exit(0);
				}
			});
			dialog = builder.create();
			break;
		case AppConstants.DIALOG_ID_UNKNOWN_ERROR:
			builder = new AlertDialog.Builder(this);
			builder.setMessage(getString(R.string.error_msg_unknow_error));
			builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					System.exit(0);
				}
			});
			dialog = builder.create();
			break;
		case AppConstants.DIALOG_ID_ERROR_NOTIFICATION:
			builder = new AlertDialog.Builder(this);
			builder.setTitle(getString(R.string.dlg_notification_title_txt));
			builder.setMessage(this.notificationMessage);
			builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					removeDialog(AppConstants.DIALOG_ID_ERROR_NOTIFICATION);
				}
			});
			builder.setCancelable(false);
			dialog = builder.create();
			break;
		}
		return dialog;
	}
}